#include "xNodeAnimation.h"
#include "xMath.h"
#include "xBone.h"
#include "xAnimationSet.h"


namespace XE
{

	xNodeAnimation::xNodeAnimation(const xString& NodeName,xAnimationSet* pParent)
		:m_NodeName(NodeName.c_str()),m_leng(0.0f),m_PosContral(NULL),
		m_pScaleContral(NULL),m_pRotaContral(NULL),m_pNode(NULL),m_pParent(pParent)
	{
		assert(m_pParent);

	}

	xNodeAnimation::~xNodeAnimation()
	{
		SafeDelete(m_pRotaContral)
		SafeDelete(m_PosContral)
		SafeDelete(m_pScaleContral)
	}


	void xNodeAnimation::CreatePositionContral()
	{
		SafeDelete(m_PosContral)

		m_PosContral = new xPositonAnimationContral();
		return;

	}

	void xNodeAnimation::CreateScaleContral()
	{
		SafeDelete(m_pScaleContral)
		m_pScaleContral  = new xScaleAnimationContral();
		return;

	}

	void xNodeAnimation::CreateRotationContral()
	{
		SafeDelete(m_pRotaContral)
		m_pRotaContral = new xRotationAnimationContral();
		return;
	}




	HRESULT xNodeAnimation::AddPositionKey(float time, const xVector3& pos)
	{
           if(m_PosContral==NULL)
			  m_PosContral = new xPositonAnimationContral();

		    xPositionKey* pPosKey = static_cast<xPositionKey*>(m_PosContral->AddKey(time));
			if(pPosKey==NULL)
				return X_FAIL;
			pPosKey->SetPosition(pos);
			if(time>m_leng)
				SetLength(time);
			return X_OK;

	}

	HRESULT xNodeAnimation::AddRotationKey(float time,const xQuaternion& quate)
	{

		if(m_pRotaContral==NULL)
			m_pRotaContral = new xRotationAnimationContral;

		xRotationKey* pRoKey = static_cast<xRotationKey*>(m_pRotaContral->AddKey(time));
		if(pRoKey==NULL)
			return X_FAIL;
		pRoKey->SetRotation(quate);
		if(time>m_leng)
				SetLength(time);
		return X_OK;

	}

	HRESULT xNodeAnimation::AddScaleKey(float time,const xVector3& scale)
	{
           if(m_pScaleContral==NULL)
			   m_pScaleContral = new xScaleAnimationContral();

		   xScaleKey* pKey = static_cast<xScaleKey*>(m_pScaleContral->AddKey(time));
		   if(pKey==NULL)
			   return X_FAIL;
		   pKey->SetPosition(scale);
		   if(time>m_leng)
			  	SetLength(time);

		   return X_OK;

	}


	HRESULT xNodeAnimation::AddMatrixKey(float time,const xMatrix& mat)
	{
		xVector3 pos,scale;
		xQuaternion quater;
		if(FAILED(xMath::DecomposeTransformationMatrix(scale,quater,pos,mat)))
			return X_FAIL;
		AddPositionKey(time,pos);
		AddRotationKey(time,quater);
		AddScaleKey(time,scale);
		return X_OK;
	}


	size_t xNodeAnimation::GetPositionKeyCount() const
	{
		if(m_PosContral==NULL)
			return 0;
		return m_PosContral->GetKeyCount();

	}

	size_t xNodeAnimation::GetRotationKeyCount() const
	{
           if(m_pRotaContral==NULL)
			   return 0;
		   return m_pRotaContral->GetKeyCount();
	}

    size_t xNodeAnimation::GetScaleKeycount() const 
	{
          if(m_pScaleContral==NULL)
			  return 0;
		  return m_pScaleContral->GetKeyCount();
	}

	HRESULT xNodeAnimation::RemoveAllKey()
	{
       RemovePositionKey();
	   RemoveRotationKey();
	   RemoveScaleKey();

	   return X_OK;
	}

	HRESULT xNodeAnimation::RemovePositionKey()
	{
         SafeDelete(m_PosContral)
		return X_OK;
	}

	HRESULT xNodeAnimation::RemoveRotationKey()
	{
		SafeDelete(m_pRotaContral)
		return X_OK;
	}

	HRESULT xNodeAnimation::RemoveScaleKey()
	{
          SafeDelete(m_pScaleContral)
		 return X_OK;
	}


	void  xNodeAnimation::CalculateKey(float time,xMatrix& mat)
	{
		time = min(time,0);
		time =  max(time,m_leng);
		xVector3 pos(0.0f,0.0f,0.0f);
		xVector3 scale(1.0f,1.0f,1.0f);
		xQuaternion quater(0.0f,0.0f,0.0f,1.0f);

		xPositionKey poskey(0.0f,xVector3(0.0f,0.0f,0.0f));
		xRotationKey quaterKey(0.0f,xQuaternion(0.0f,0.0f,0.0f,1.0f));
		xScaleKey  scalekey(0.0f,xVector3(0.0f,0.0f,0.0f));

		if(m_PosContral!=NULL)
		{
			m_PosContral->CalculateKey(time,&poskey);
		}
		if(m_pScaleContral!=NULL)
		{
			m_pScaleContral->CalculateKey(time,&scalekey);
		}
		if(m_pRotaContral!=NULL)
		{
			m_pRotaContral->CalculateKey(time,&quaterKey);
		}

		xMath::BuildTransformationMatrix(mat,poskey.GetPosition(),quaterKey.GetRotation(),scalekey.GetPosition());
		return;

	}

	void xNodeAnimation::SetLength(float time)
	{
		m_leng=time; 
		m_pParent->_notifyLengthChange(m_leng);
	}


	HRESULT xNodeAnimation::SetTime(float time,float factor)
	{
		if(m_pNode==NULL)
			return X_FAIL;
        xPositionKey poskey;
		xScaleKey scalekey;
		xRotationKey	 quatekey;
		xMatrix AnimationMatrix,outMatrix;
		xMath::MatrixIdentity(AnimationMatrix);
		if(m_pScaleContral!=NULL)
		{
			if(SUCCEEDED(m_pScaleContral->CalculateKey(time,&scalekey)))
			{
				//   m_pNode->SetScale(scalekey.GetPosition());
				D3DXMatrixScaling(&outMatrix,scalekey.GetPosition().x,scalekey.GetPosition().y,scalekey.GetPosition().z);
				AnimationMatrix*=outMatrix;
			}

		}
		if(m_pRotaContral!=NULL)
		{
			if(SUCCEEDED(m_pRotaContral->CalculateKey(time,&quatekey)))
			{
				D3DXMatrixRotationQuaternion(&outMatrix,&(quatekey.GetRotation()));
				AnimationMatrix*=outMatrix;
			}
		}

		if(m_PosContral!=NULL)
		{
           if( SUCCEEDED(m_PosContral->CalculateKey(time,&poskey)))
		   {
			   D3DXMatrixTranslation(&outMatrix,poskey.GetPosition().x,poskey.GetPosition().y,poskey.GetPosition().z);
			   AnimationMatrix*=outMatrix;

			 //  m_pNode->SetPosition(poskey.GetPosition());
		   }
		}

	 //  xMatrix inver;
	  // D3DXMatrixInverse(&inver,NULL,static_cast<xBone*>(m_pNode)->GetOffsetMatrix());
	   
          AnimationMatrix-=  *(static_cast<xBone*>(m_pNode)->GetOffsetMatrix());
		  AnimationMatrix*=factor;
		  //AnimationMatrix*=0.5;
		  xMatrix finshMat = *(static_cast<xBone*>(m_pNode)->GetOffsetMatrix())+AnimationMatrix;   
		 m_pNode->SetLocalMatrix(finshMat);



	
		



		return X_OK;

	}



}